package com.qingcheng.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.qingcheng.dao.BrandMapper;
import com.qingcheng.dao.SpecMapper;
import com.qingcheng.service.goods.SkuSearchService;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class SkuSearchServiceImpl implements SkuSearchService {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Autowired
    private BrandMapper brandMapper;

    @Autowired
    private SpecMapper specMapper;

    @Override
    public Map search(Map<String, String> searchMap) {
        //封装查询请求
        SearchRequest searchRequest = new SearchRequest("sku");
        searchRequest.types("doc");
        SearchSourceBuilder builder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();//布尔查询构建器
        //关键词查询
        if (searchMap.get("keywords") != null && !"".equals(searchMap.get("keywords"))) {
            MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("name", searchMap.get("keywords"));
            boolQueryBuilder.must(matchQueryBuilder);
        }
        //商品分类筛选
        if (searchMap.get("category") != null && !"".equals(searchMap.get("category"))) {
            TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("categoryName", searchMap.get("category"));
            boolQueryBuilder.filter(termQueryBuilder);
        }
        //品牌分类筛选
        if (searchMap.get("brand") != null && !"".equals(searchMap.get("brand"))) {
            TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("brandName", searchMap.get("brand"));
            boolQueryBuilder.filter(termQueryBuilder);
        }
        //规格筛选
        for (String key : searchMap.keySet()) {
            if(searchMap.get(key).startsWith("spec.")) {
                //前后端规定以spec.开头的都是规格
                TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery(key+".keyword", searchMap.get(key));
                boolQueryBuilder.filter(termQueryBuilder);
            }
        }
        //价格筛选
        if(searchMap.get("price") != null) {
            String[] price = searchMap.get("price").split("-");
            if(!"0".equals(price[0])) {
                RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("price").gte(price[0] + "00");
                boolQueryBuilder.filter(rangeQueryBuilder);
            }
            if(!"*".equals(price[1])) {
                RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("price").lte(price[1] + "00");
                boolQueryBuilder.filter(rangeQueryBuilder);
            }
        }
        //查询
        builder.query(boolQueryBuilder);
        //分页
        int currentPage = Integer.parseInt(searchMap.get("currentPage")); //当前页码
        int pageSize = 30; //一页展示的数据
        int fromIndex = (currentPage - 1) * pageSize; //每页第一个数据的索引
        builder.from(fromIndex);
        builder.size(pageSize);
        //排序
        String sort = searchMap.get("sort"); //排序字段
        String sortOrder = searchMap.get("sortOrder"); //排序规则
        if(!"".equals(sort)) {
            builder.sort(sort, SortOrder.valueOf(sortOrder));
        }
        //高亮显示
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("name").preTags("<font style='color:red'>").postTags("</font>");
        builder.highlighter(highlightBuilder);

        //聚合查询
        TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms("sku_category").field("categoryName");
        builder.aggregation(termsAggregationBuilder);
        searchRequest.source(builder);
        //封装查询结果
        Map resultMap = new HashMap();
        SearchResponse searchResponse = null;
        try {
            searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            SearchHits searchHits = searchResponse.getHits();
            long totalHits = searchHits.totalHits; //总计数
            System.out.println("总计数:" + totalHits);
            SearchHit[] hits = searchHits.getHits(); //获得hits数组
            //商品列表
            List<Map<String, Object>> resultList = new ArrayList<Map<String, Object>>();
            for (SearchHit hit : hits) {
                Map<String, Object> hitMap = hit.getSourceAsMap(); //得到的所有sku
                Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                HighlightField name = highlightFields.get("name");
                Text[] fragments = name.fragments();
                hitMap.put("name",fragments[0].toString()); //高亮显示
                resultList.add(hitMap);
            }
            resultMap.put("rows", resultList);

            //商品分类列表
            Aggregations aggregations = searchResponse.getAggregations();
            Map<String, Aggregation> aggregationMap = aggregations.getAsMap();
            Terms terms = (Terms) aggregationMap.get("sku_category");
            List<? extends Terms.Bucket> buckets = terms.getBuckets(); //获得所有buckets
            List<String> categoryList = new ArrayList<>();
            for (Terms.Bucket bucket : buckets) {
                categoryList.add(bucket.getKeyAsString()); //获得商品分类的名字,放入集合中
            }
            resultMap.put("categoryList", categoryList);

            String categoryName = "";
            if (searchMap.get("categoryName") == null) {
                //走这说明用户没有点商品分类,展示第一个分类的品牌
                if (categoryList.size() > 0)
                    categoryName = categoryList.get(0);
            } else
                //走这里说明用户点了一个分类,需要展示这个分类的品牌
                categoryName = searchMap.get("categoryName");

            //品牌列表
            if (searchMap.get("brand") == null) {
                //通过名字查找品牌集合
                List<Map> brandList = brandMapper.findListByCategoryName(categoryName);
                resultMap.put("brandList", brandList);
            }

            //规格列表
            List<Map> specList = specMapper.findListByCategoryName(categoryName);
            for (Map spec : specList) { //转换option的格式为数组形式,再重新放入specMap中
                String[] options = ((String) spec.get("options")).split(","); //option数组
                spec.put("options",options);
            }
            resultMap.put("specList",specList);

            //分页
            long totalCount = searchHits.getTotalHits();  //总计数
            int pageCount = (int) Math.ceil((double) (totalCount / pageSize)); //总页数
            int beginPage; //起始页
            int endPage; //结束页
            if(pageCount <= 5) { //总页数小于5
                beginPage = 1;
                endPage = pageCount;
            } else { //总页数大于5
                beginPage = currentPage - 2;
                endPage = currentPage + 2;
                if(endPage > pageCount) { //如果结束页大于总页数
                    endPage = pageCount;
                    beginPage = endPage - 4;
                }
                if(beginPage < 1) { //如果起始页小于1
                    beginPage = 1;
                    endPage = beginPage + 4;
                }
            }
            resultMap.put("beginPage",beginPage);
            resultMap.put("endPage",endPage);
            resultMap.put("pageCount",pageCount);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return resultMap;
    }
}
